<template>
  <div class="v-input">
    <input
      v-if="tag !== 'textarea'"
      class="v-input_inner"
      :class="{ 'v-input_error': inputRef.error }"
      :value="inputRef.val"
      v-bind="$attrs"
      @input="updateValue"
      @blur="validateInput"
    />
    <textarea
      v-else
      class="v-input_textarea"
      :class="{ 'v-input_error': inputRef.error }"
      :value="inputRef.val"
      v-bind="$attrs"
      @input="updateValue"
      @blur="validateInput"
    ></textarea>
    <span class="v-input_hint" v-if="inputRef.error">
      {{ inputRef.message }}
    </span>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, PropType, reactive } from 'vue'
import { emitter } from './ValidateForm.vue'
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
interface RuleProp {
  type: 'required' | 'email' | 'rang' | 'custom';
  message: string;
  validator?: () => boolean;
}
export type RulesProp = RuleProp[]
export type TagType = 'input' | 'textarea'

export default defineComponent({
  inheritAttrs: false,
  props: {
    modelValue: String,
    rules: {
      type: Array as PropType<RulesProp>
    },
    tag: {
      type: String as PropType<TagType>,
      default: 'input'
    }
  },
  setup(props, context) {
    const inputRef = reactive({
      val: props.modelValue || '',
      error: false,
      message: ''
    })
    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue
      context.emit('update:modelValue', targetValue)
    }
    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every(rule => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (inputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(inputRef.val)
              break
            case 'rang':
              passed = (inputRef.val.trim().length > 5 && inputRef.val.trim().length < 17)
              break
            case 'custom':
              passed = rule.validator ? rule.validator() : true
              break
            default:
              break
          }
          return passed
        })
        inputRef.error = !allPassed
        return allPassed
      }
      return true
    }
    onMounted(() => {
      emitter.emit('form-item-created', validateInput)
    })
    return { inputRef, validateInput, updateValue }
  }
})
</script>

<style lang="scss" scoped>
.v-input {
  width: 100%;
  height: 100%;
  position: relative;
  font-size: 0.14rem;
  &_inner {
    -webkit-appearance: none;
    background-color: #fff;
    background-image: none;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    box-sizing: border-box;
    color: #606266;
    display: inline-block;
    font-size: inherit;
    height: 0.4rem;
    line-height: 0.4rem;
    outline: none;
    padding: 0 0.15rem;
    transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    width: 100%;
    &:focus {
      outline: none;
      border-color: #409eff;
    }
  }
  &_textarea {
    resize: none;
    width: 100%;
    min-height: 1rem;
    padding: 0.1rem;
    -webkit-appearance: none;
    background-color: #fff;
    background-image: none;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    box-sizing: border-box;
    color: #606266;
    &:focus {
      outline: none;
      border-color: #409eff;
    }
  }
  &_error {
    border-color: red;
  }
  &_hint {
    font-size: 0.12rem;
    color: red;
    margin-top: 0.1rem;
    display: block;
  }
}
</style>
